#include <iostream>
#include <memory>
#include <functional>
#include "LOG.hpp"
#include "Protocol.hpp"
#include "TcpServer.hpp"
#include"Calculate.hpp"
using namespace protocol_ns;
using callback_t = std::function<Response(const Request &req)>;

void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << "local_port\n"<< std::endl;
}
class Service
{
public:
    Service(callback_t cb)
    :_cb(cb)
    {
    }
    void ServiceHelper(socket_ptr sockptr, InetAddr client)
    {
        int sockfd = sockptr->SockFd();
        LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.Ip().c_str(), client.Port(), sockfd);
        std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "] ";

        std::string inbuffer;
        while (true)
        {
            sleep(1);
            Request req;
            //读取数据
            int n = sockptr->Recv(&inbuffer);
            if (n < 0)
            {
                LOG(DEBUG, "client %s quit\n", clientaddr.c_str());
                break;
            }
            //分析数据是否完整
            std::string package = Decode(inbuffer);
            if (package.empty())
                continue;
            std::cout<<"request string\n"<<package<<std::endl;
            // 一定获得了完整json串
            //反序列化
            req.DeSerialize(package);

            //业务处理
            Response resp = _cb(req);

            //处理完发回去(响应)之前要序列化
            std::string send_str;
            resp.Serialize(&send_str);
            std::cout<<"response Serialize:"<<std::endl;
            std::cout<<send_str<<std::endl;


            //保证响应完整(添加报头)
            send_str = Encode(send_str);
            std::cout<<"response Encode:"<<std::endl;
            std::cout<<send_str<<std::endl;

            sockptr->Send(send_str);
        }
    }
private:
    callback_t _cb;
};


int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    EnableScreen();
    uint16_t port = std::stoi(argv[1]);
    Calculate cal;
    Service calservice(std::bind(&Calculate::Excute,&cal,std::placeholders::_1));
    io_service_t service = std::bind(&Service::ServiceHelper,&calservice,std::placeholders::_1,std::placeholders::_2);
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service);
    tsvr->Loop();
    return 0;
}
    